#ifndef PARSER_H
#define PARSER_H

#include <vector>
#include <memory>
#include <stdexcept>
#include <Lexer.h>
#include <resource.h>

namespace PARSER
{
    enum Statement_Type
    {
        CONST_DECL,
        VAR_DECL,
        PROC_DECL,
        ASSIGN_STAT,
        CALL_STAT,
        WRITE_STAT,
        READ_STAT,
        WHILE_STAT,
        IF_STAT,
    };

    enum ASTNode_Type
    {
        BLOCK,
        STATEMENT,
        EXPRESSION
    };

    enum SymbolType
    {
        CONST,
        VAR,
        PROC,
        CALL,
        CONST_ARRAY,
        VAR_ARRAY
    };

    class AST_Node
    {
    public:
        ASTNode_Type astnode_type;
        virtual ASTNode_Type AST_get_type() const
        {
            return astnode_type;
        }
        // 重载 << 运算符
        friend std::ostream &operator<<(std::ostream &os, const AST_Node &node);
    };

    class Expression : public AST_Node
    {
    public:
        std::string express;

        int evaluate() const
        {
            // 实现表达式求值逻辑
            return 0; // 示例返回值
        }
        // 重载 << 运算符
        friend std::ostream &operator<<(std::ostream &os, const Expression &expr)
        {
            os << expr.express;
            return os;
        }
    };

    class Symbol
    {
    public:
        std::string name;
        int value;
        SymbolType type;
        bool is_globle = false;
        // 重载 << 运算符
        friend std::ostream &operator<<(std::ostream &os, const Symbol &symbol)
        {
            os << "Name: " << symbol.name << ", Value: " << symbol.value << ", Type: " << symbol.type;
            return os;
        }
    };

    class SymbolTable
    {
    public:
        SymbolTable() = default;

        void add_symbol(const std::string &name, int value, SymbolType type,bool is_globle);
        int get_symbol_value(const std::string &name) const;
        std::shared_ptr<Symbol> get_symbol_by_name(std::string name) const;
        bool symbol_exists(const std::string &name) const;
        std::string get_end_name();
        void merge_with_symbol_table(const std::shared_ptr<SymbolTable> &other);
        bool name_is_in_symbol_table(const std::string &name);

        // 重载 << 运算符
        friend std::ostream &operator<<(std::ostream &os, const SymbolTable &symbolTable)
        {
            for (const auto &symbol : symbolTable.symbols)
            {
                os << symbol << std::endl;
            }
            return os;
        }

    private:
        std::vector<Symbol> symbols;
    };

    class Statement : public AST_Node
    {
    public:
        int line_num = 0;
        int column_num = 0;
        virtual Statement_Type statment_get_type() const
        {

        } // 纯虚函数，要求子类实现
        void set_line_num(int line_num) { this->line_num = line_num; }
        void set_column_num(int column_num) { this->column_num = column_num; }
    };

    // 变量类型
    enum class VariableType
    {
        INT32,
        INT64,
        FLOAT32,
        FLOAT64,
        BOOLEAN
    };
    // 重载 << 运算符
    inline std::ostream &operator<<(std::ostream &os, const VariableType &varType)
    {
        switch (varType)
        {
        case VariableType::INT32:
            os << "INT32";
            break;
        case VariableType::INT64:
            os << "INT64";
            break;
        case VariableType::FLOAT32:
            os << "FLOAT32";
            break;
        case VariableType::FLOAT64:
            os << "FLOAT64";
            break;
        case VariableType::BOOLEAN:
            os << "BOOLEAN";
            break;
        default:
            os << "UNKNOWN";
            break;
        }
        return os;
    }

    class ConstDecl : public Statement
    {
    public:
        std::string name;
        int value;
        int line_num;
        int column_num;
        VariableType variable_type;
        int size = 0;
        std::vector<int> array_values;
        bool is_array = false;
        bool is_globle = false;
        void set_size(int size) { this->size = size; }
        void set_variable_type(VariableType variable_type) { this->variable_type = variable_type; }
        void set_column_num(int column_num) { this->column_num = column_num; }
        void set_line_num(int line_num) { this->line_num = line_num; }
        void generate_llvmir(int level) const;
        ConstDecl(const std::string &name, int value,bool globle) : name(name), value(value), line_num(0), column_num(0), variable_type(VariableType::INT32)
        {
            astnode_type = STATEMENT;
            this->is_globle = globle;
        }

        Statement_Type statment_get_type() const override { return CONST_DECL; }

        // 重载 << 运算符
        friend std::ostream &operator<<(std::ostream &os, const ConstDecl &constDecl)
        {
            os << "ConstDecl Name: " << constDecl.name;
            if (constDecl.is_array)
            {
                os << ", Size: " << constDecl.size << ", Values: {";
                for (size_t i = 0; i < constDecl.array_values.size(); ++i)
                {
                    os << constDecl.array_values[i];
                    if (i != constDecl.array_values.size() - 1)
                        os << ", ";
                }
                os << "}";
            }
            else
            {
                os << ", Value: " << constDecl.value;
            }
            os << ", VariableType: " << static_cast<int>(constDecl.variable_type);
            return os;
        }
    };

    class VarDecl : public Statement
    {
    public:
        std::string name;
        int line_num;
        int column_num;
        VariableType variable_type;
        int size = 0;                  // 数组大小，对于数组变量
        bool is_array = false;         // 是否为数组变量
        std::vector<int> array_values; // 数组初始值
        int value = 0;                 // 对于标量变量的初始值
        bool is_globle = false;
        void set_size(int size) { this->size = size; }
        void set_variable_type(VariableType variable_type) { this->variable_type = variable_type; }
        void set_column_num(int column_num) { this->column_num = column_num; }
        void set_line_num(int line_num) { this->line_num = line_num; }
        void generate_llvmir(int level) const;
        VarDecl(const std::string &name,bool globle) : name(name), line_num(0), column_num(0), variable_type(VariableType::INT32), is_array(false)
        {
            astnode_type = STATEMENT;
            this->is_globle = globle;
        }

        Statement_Type statment_get_type() const override { return VAR_DECL; }

        // 重载 << 运算符
        friend std::ostream &operator<<(std::ostream &os, const VarDecl &varDecl)
        {
            os << "VarDecl Name: " << varDecl.name;
            if (varDecl.is_array)
            {
                os << ", Size: " << varDecl.size << ", Values: {";
                for (size_t i = 0; i < varDecl.array_values.size(); ++i)
                {
                    os << varDecl.array_values[i];
                    if (i != varDecl.array_values.size() - 1)
                        os << ", ";
                }
                os << "}";
            }
            else
            {
                os << ", Value: " << varDecl.value;
            }
            os << ", VariableType: " << static_cast<int>(varDecl.variable_type);
            return os;
        }
    };

    class ProcDecl : public Statement
    {
    public:
        std::string name;
        std::vector<VarDecl> params;
        int line_num;
        Statement_Type statment_get_type() const override { return PROC_DECL; }
        int column_num;
        void set_column_num(int column_num) { this->column_num = column_num; }
        void set_line_num(int line_num) { this->line_num = line_num; }
        std::shared_ptr<class Block> block;
        ProcDecl(const std::string &name) : name(name), line_num(0), column_num(0) { astnode_type = STATEMENT; }
        void generate_llvmir() const;
        // 重载 << 运算符
        friend std::ostream &operator<<(std::ostream &os, const ProcDecl &procDecl)
        {
            os << "ProcDecl Name: " << procDecl.name << "\n";
            return os;
        }
    };

    class Block : public AST_Node
    {
    public:
        std::shared_ptr<Block> get_parent();
        std::shared_ptr<SymbolTable> symbol_table;
        int print_level = -1;
        Block()
        {
            astnode_type = ASTNode_Type::BLOCK;
        }
        void set_parent(std::shared_ptr<Block> parent) { this->parent = parent; }
        void add_const_decl(std::shared_ptr<ConstDecl> const_decl);
        void add_var_decl(std::shared_ptr<VarDecl> var_decl);
        void add_proc_decl(std::shared_ptr<ProcDecl> proc_decl);
        void add_statement(std::shared_ptr<Statement> statement);
        void set_name(const std::string &name) { this->name = name; }
        void set_symbol_table(std::shared_ptr<SymbolTable> symbol_table) { this->symbol_table = symbol_table; }
        void add_symbol(const std::string &name, int value, SymbolType type,bool is_globle) { symbol_table->add_symbol(name, value, type,is_globle); }
        void merge_with_block(const std::shared_ptr<Block> &other);
        void add_ast_node(std::shared_ptr<AST_Node> ast_node);
        void add_child(std::shared_ptr<Block> child)
        {
            ast_nodes.push_back(std::static_pointer_cast<AST_Node>(child));
        }
        std::string get_name() { return name; }
        void print_AstNode() const;
        // 重载 << 运算符
        friend std::ostream &operator<<(std::ostream &os, const Block &block)
        {
            os << "Block Name: " << block.name << "\n";
            block.print_AstNode();
            return os;
        }
        std::vector<std::shared_ptr<AST_Node>> ast_nodes;
    private:
        std::shared_ptr<Block> parent;
        std::string name;
    };

    class Program
    {
    public:
        std::shared_ptr<Block> boot_block;
        int index = 0;
        // 构造函数
        Program()
        {
            boot_block = std::make_shared<Block>();
            boot_block->set_symbol_table(std::make_shared<SymbolTable>());
        }

        // 重载 << 运算符
        friend std::ostream &operator<<(std::ostream &os, const Program &program)
        {
            os << "Program Main Block: " << *program.boot_block;
            return os;
        }
    };

    class Parser
    {
    public:
        Parser(std::vector<LEXER::Token> tokens) : tokens(tokens), current_token_index(0)
        {
            if (!tokens.empty())
            {
                current_token = tokens[current_token_index];
            }
        }
        RESOURCE::Uint_Allocator uint_allocator_for_while = RESOURCE::Uint_Allocator(0);
        RESOURCE::Uint_Allocator uint_allocator_for_if = RESOURCE::Uint_Allocator(0);
        std::shared_ptr<Program> parse_program();
        LEXER::TokenType get_next_token_type();
        int statement_num = 0;
        void parse_block();
        void parse_assign();
        void parse_const_decl();
        void parse_var_decl();
        void parse_proc_decl();
        void parse_statement();
        bool is_token_end();
        void update_current_token();
        void update_Block_to_Child();
        void parse_write();
        void parse_call();
        void parse_while();
        std::shared_ptr<Expression> parse_expression(bool is_while, bool is_if);
        void set_current_block_to_parent();
        void update_Block_to_parent();
        bool is_in_procedure;
        bool is_in_while;
        std::string get_while_name();
        std::string get_if_name();
        void throw_error(const std::string &msg);
        std::shared_ptr<Symbol> get_symbol_in_current_and_parent(const std::string &name) const;
        void parse_read();
        void parse_if();
        bool is_begin;
        void generate_llvmir(std::shared_ptr<Block> block,int level) const;
        std::shared_ptr<Block> adjust_boot_block(std::shared_ptr<Block> block);
    private:
        std::vector<LEXER::Token> tokens;
        int current_token_index;
        int level = 0;
        LEXER::Token current_token;
        std::shared_ptr<Block> current_block;
        std::string last_procedure_name;
    };

    class Assign : public Statement
    {
    public:
        Statement_Type statment_get_type() const override { return ASSIGN_STAT; }
        std::shared_ptr<Symbol> target;
        std::shared_ptr<Expression> value;

        Assign(const std::shared_ptr<Symbol> target, std::shared_ptr<Expression> value) : target(target), value(std::move(value))
        {
            astnode_type = STATEMENT;
        }

        // 重载 << 运算符
        friend std::ostream &operator<<(std::ostream &os, const Assign &assign)
        {
            os << "Assign Target: " << *assign.target << ", Value: " << *assign.value;
            return os;
        }
    };

    class Call : public Statement
    {
    public:
        Statement_Type statment_get_type() const override { return CALL_STAT; }
        std::string proc_name;
        std::vector<std::shared_ptr<Expression>> args;
        void generate_llvmir() const;
        Call(const std::string &proc_name) : proc_name(proc_name)
        {
            astnode_type = STATEMENT;
        }

        // 重载 << 运算符
        friend std::ostream &operator<<(std::ostream &os, const Call &call)
        {
            os << "Call Proc Name: " << call.proc_name;
            return os;
        }
    };

    class While : public Statement
    {
    public:
        Statement_Type statment_get_type() const override { return WHILE_STAT; }
        std::shared_ptr<Expression> condition;

        While(std::shared_ptr<Expression> condition) : condition(std::move(condition))
        {
            astnode_type = STATEMENT;
        }

        // 重载 << 运算符
        friend std::ostream &operator<<(std::ostream &os, const While &whileStmt)
        {
            os << "While Condition: " << *whileStmt.condition;
            return os;
        }
    };

    class If : public Statement
    {
    public:
        std::string name;
        Statement_Type statment_get_type() const override { return IF_STAT; }
        std::shared_ptr<Expression> condition;
        void generate_llvmir();
        If(std::shared_ptr<Expression> condition)
            : condition(std::move(condition))
        {
            astnode_type = STATEMENT;
        }

        // 重载 << 运算符
        friend std::ostream &operator<<(std::ostream &os, const If &ifStmt)
        {
            os << "If Condition: " << *ifStmt.condition;
            return os;
        }
    };

    class Write : public Statement
    {
    public:
        Statement_Type statment_get_type() const override { return WRITE_STAT; }
        std::shared_ptr<Symbol> ident;
        Write(std::shared_ptr<Symbol> ident) : ident(std::move(ident))
        {
            astnode_type = STATEMENT;
        }
        void generate_llvmir() const;
        // 重载 << 运算符
        friend std::ostream &operator<<(std::ostream &os, const Write &writeStmt)
        {
            os << "Write Ident: " << *writeStmt.ident;
            return os;
        }
    };

    class Read : public Statement
    {
    public:
        Statement_Type statment_get_type() const override { return READ_STAT; }
        std::shared_ptr<Symbol> ident;
        Read(std::shared_ptr<Symbol> ident) : ident(std::move(ident))
        {
            astnode_type = STATEMENT;
        }
        void generate_llvmir() const;
        // 重载 << 运算符
        friend std::ostream &operator<<(std::ostream &os, const Read &readStmt)
        {
            os << "Read Ident: " << *readStmt.ident;
            return os;
        }
    };
} // namespace PARSER

#endif // PARSER_H
